`timescale 1ns/1ps
`default_nettype none

/* NOTE:
* - 扫描译码
*/

module cxy_scan_decoder (
    // system signal
    input  wire         I_sclk,  // 125M
    input  wire         I_rst_n,
    // config
    input  wire [5:0]   I_cfg_scan_max,         // 最大扫描id
    input  wire [2:0]   I_cfg_decode_type,      // 译码方式
    input  wire [15:0]  I_cfg_decode_param0,    // 译码参数0
    input  wire [15:0]  I_cfg_decode_param1,    // 译码参数1
    input  wire [15:0]  I_cfg_deghost_ctrl_dly, // 消影信号延迟
    input  wire [15:0]  I_cfg_deghost_ctrl_len, // 消影信号长度
    // control
    input  wire         I_scan_prep,            // 准备换行
    input  wire [5:0]   I_scan_num,             // 行id
    input  wire         I_scan_commit,          // 执行换行
    // scan out
    output wire         O_deghost_ctrl,
    output wire [4:0]   O_scan_out
    );
//------------------------Parameter----------------------
localparam [2:0]
    MODE_138  = 0, // 138译码
    MODE_LOW  = 1, // 直接输出（低）
    MODE_HIGH = 2, // 直接输出（高）
    MODE_595  = 3, // 595译码
    MODE_5958 = 4, // 5958译码
    MODE_5266 = 5; // SM5266P

//------------------------Local signal-------------------
wire [9:0]  cfg_decode_param0;
wire [9:0]  cfg_decode_param1;

reg  [5:0]  scan_result;
reg  [4:0]  scan_out;

reg  [9:0]  commit_cnt;

reg         clk_595;
reg         dat_595;

reg         clk_5958;
reg         dat_5958;
reg         oe_5958;

reg         bk_5266;    // c
reg         din_5266;   // b
reg         dck_5266;   // a
reg         d_5266;
reg         e_5266;
reg         pad_flag_5266;
reg  [5:0]  pad_cnt_5266;
wire [9:0]  pad_param0;
wire [9:0]  pad_param1;

reg         dly_en;
reg         ctrl_en;
reg  [9:0]  dly_cnt;
reg  [9:0]  ctrl_cnt;

//------------------------Instantiation------------------

//------------------------Body---------------------------
assign cfg_decode_param0 = I_cfg_decode_param0[9:0];
assign cfg_decode_param1 = I_cfg_decode_param1[9:0];

assign O_scan_out = scan_out;

//scan_result[5:0]
always@(posedge I_sclk or negedge I_rst_n)
    if(!I_rst_n)
        scan_result <= 'b0;
    else if(I_scan_prep)
    case(I_cfg_decode_type)
        MODE_LOW:   scan_result <= ~(5'b1 << I_scan_num[2:0]);
        MODE_HIGH:  scan_result <=   5'b1 << I_scan_num[2:0];
        default:    scan_result <= I_scan_num;
    endcase

//scan_out[4:0]
always@(posedge I_sclk or negedge I_rst_n)
    if(!I_rst_n)
        scan_out <= 'b0;
    else
    case(I_cfg_decode_type)
        MODE_595:   scan_out <= {dat_595, clk_595};
        MODE_5958:  scan_out <= {dat_5958, oe_5958, clk_5958};
        MODE_5266:  scan_out <= {e_5266, d_5266, bk_5266, din_5266, dck_5266};

        default:
            if(I_scan_commit)
                scan_out <= scan_result[4:0];
    endcase

//commit_cnt[9:0]
always@(posedge I_sclk or negedge I_rst_n)
    if(!I_rst_n)
        commit_cnt <= 10'd1023;
    else if(I_scan_commit)
        commit_cnt <= 10'd1;
    else if(commit_cnt<1023)
        commit_cnt <= commit_cnt + 1'b1;

//clk_595
always@(posedge I_sclk or negedge I_rst_n)
    if(!I_rst_n)
        clk_595 <= 'b0;
    else if(commit_cnt==cfg_decode_param0)
        clk_595 <= 1'b1;
    else if(commit_cnt==cfg_decode_param1)
        clk_595 <= 'b0;

//dat_595
always@(posedge I_sclk or negedge I_rst_n)
    if(!I_rst_n)
        dat_595 <= 1'b1;
    else if(I_scan_commit)
    begin
        if(scan_result==I_cfg_scan_max)
            dat_595 <= 'b0;
        else
            dat_595 <= 1'b1;
    end

//clk_5958
always@(posedge I_sclk or negedge I_rst_n)
    if(!I_rst_n)
        clk_5958 <= 'b0;
    else if(commit_cnt==cfg_decode_param0)
        clk_5958 <= 1'b1;
    else if(commit_cnt==cfg_decode_param1)
        clk_5958 <= 'b0;

//dat_5958
always@(posedge I_sclk or negedge I_rst_n)
    if(!I_rst_n)
        dat_5958 <= 'b0;
    else if(I_scan_commit)
    begin
        if(scan_result==0)
            dat_5958 <= 1'b1;
        else
            dat_5958 <= 'b0;
    end

//oe_5958
always@(posedge I_sclk or negedge I_rst_n)
    if(!I_rst_n)
        oe_5958 <= 1'b1;
    else if(I_scan_commit)
        oe_5958 <= 1'b1;
    else if(commit_cnt==cfg_decode_param1)
        oe_5958 <= 'b0;

assign pad_param0 = cfg_decode_param0 + {~I_cfg_scan_max[2:0], 3'd7};
assign pad_param1 = cfg_decode_param1 + {~I_cfg_scan_max[2:0], 3'd7};

//bk_5266
always@(posedge I_sclk or negedge I_rst_n)
    if(!I_rst_n)
        bk_5266 <= 'b0;
    else if(I_scan_commit)
        bk_5266 <= 1'b1;
    else if(  ( pad_flag_5266 && commit_cnt==pad_param1       )
            ||(!pad_flag_5266 && commit_cnt==cfg_decode_param1))
        bk_5266 <= 'b0;

//din_5266
always@(posedge I_sclk or negedge I_rst_n)
    if(!I_rst_n)
        din_5266 <= 'b0;
    else if(pad_flag_5266)
        begin
            if(pad_cnt_5266==1)
                din_5266 <= 1'b1;
            else if(commit_cnt==pad_param1)
                din_5266 <= 'b0;
        end
    else
        begin
            if(commit_cnt==1 && scan_result[2:0]==0)
                din_5266 <= 1'b1;
            else if(commit_cnt==cfg_decode_param1)
                din_5266 <= 'b0;
        end

//dck_5266
always@(posedge I_sclk or negedge I_rst_n)
    if(!I_rst_n)
        dck_5266 <= 'b0;
    else if(pad_cnt_5266[2:0]==7)
        dck_5266 <= 1'b1;
    else if(pad_cnt_5266[2:0]==3)
        dck_5266 <= 1'b0;
    else if(pad_flag_5266)
        begin
            if(commit_cnt==pad_param0)
                dck_5266 <= 1'b1;
            else if(commit_cnt==pad_param1)
                dck_5266 <= 'b0;
        end
    else
        begin
            if(commit_cnt==cfg_decode_param0)
                dck_5266 <= 1'b1;
            else if(commit_cnt==cfg_decode_param1)
                dck_5266 <= 'b0;
        end

//d_5266
always@(posedge I_sclk or negedge I_rst_n)
    if(!I_rst_n)
        d_5266 <= 'b0;
    else if(  ( pad_flag_5266 && commit_cnt==pad_param0       )
            ||(!pad_flag_5266 && commit_cnt==cfg_decode_param0))
        d_5266 <= scan_result[3];

//e_5266
always@(posedge I_sclk or negedge I_rst_n)
    if(!I_rst_n)
        e_5266 <= 'b0;
    else if(  ( pad_flag_5266 && commit_cnt==pad_param0       )
            ||(!pad_flag_5266 && commit_cnt==cfg_decode_param0))
        e_5266 <= scan_result[4];

//pad_flag_5266
always@(posedge I_sclk or negedge I_rst_n)
    if(!I_rst_n)
        pad_flag_5266 <= 'b0;
    else if(I_cfg_scan_max<=7 || I_cfg_scan_max[2:0]==7)
        pad_flag_5266 <= 'b0;
    else if(I_scan_commit)
    begin
        if(scan_result==0)
            pad_flag_5266 <= 1'b1;
        else
            pad_flag_5266 <= 'b0;
    end

//pad_cnt_5266[5:0]
always@(posedge I_sclk or negedge I_rst_n)
    if(!I_rst_n)
        pad_cnt_5266 <= 'b0;
    else if(pad_flag_5266 && commit_cnt==cfg_decode_param0-2)
        pad_cnt_5266 <= {~I_cfg_scan_max[2:0], 3'd0};
    else if(pad_cnt_5266 != 0)
        pad_cnt_5266 <= pad_cnt_5266 - 1'b1;
//****************************************************************
assign O_deghost_ctrl = ctrl_en;

//dly_en
always@(posedge I_sclk or negedge I_rst_n)
    if(!I_rst_n)
        dly_en <= 'b0;
    else if(I_scan_commit)
        dly_en <= 1'b1;
    else if(dly_cnt==I_cfg_deghost_ctrl_dly[9:0])
        dly_en <= 'b0;

//dly_cnt[9:0]
always@(posedge I_sclk or negedge I_rst_n)
    if(!I_rst_n)
        dly_cnt <= 'b0;
    else if(dly_en==1)
        dly_cnt <= dly_cnt + 1'b1;
    else
        dly_cnt <= 'b0;

//ctrl_en
always@(posedge I_sclk or negedge I_rst_n)
    if(!I_rst_n)
        ctrl_en <= 'b0;
    else if(dly_en==1 && dly_cnt==I_cfg_deghost_ctrl_dly[9:0])
        ctrl_en <= 1'b1;
    else if(ctrl_cnt==I_cfg_deghost_ctrl_len[9:0])
        ctrl_en <= 'b0;

//ctrl_cnt[9:0]
always@(posedge I_sclk or negedge I_rst_n)
    if(!I_rst_n)
        ctrl_cnt <= 'b0;
    else if(ctrl_en==1)
        ctrl_cnt <= ctrl_cnt + 1'b1;
    else
        ctrl_cnt <= 'b0;

//****************************************************************
endmodule

`default_nettype wire

// vim:set ts=4 sw=4 et fenc=utf-8 fdm=marker:
